<?php
namespace core\models;
/**
 * 信用卡验证
 */
class Widget_CreditCard {
    public function __construct() {

    }

    /**
     * 判断是否是信用卡
     * @param string     $number      信用卡号
     * @param bool|false $checkExpiry 是否判断有效期，默认不判断
     * @param string     $expiry      信用卡有效日期，采用07/12或0712这样的格式
     * @return bool
     */
    public function isCreditCard($number, $checkExpiry = false, $expiry = '') {
        $expiry = preg_replace('/[^\d]/', '', $expiry);
        if ($checkExpiry == true && mktime(
                0, 0, 0, substr($expiry, 0, 2), date("t"),
                substr($expiry, 2, 2)
            ) < time()
        ) {
            return false;
        }
        //$r = $this->onlyVerifyCardNum($number);
        $r = $this->luhnVerifyCardNum($number);
        return $r;
    }

    /**
     * 用Luhn算法判断信用卡是否合法
     * 此方法最快
     * @param $number
     * @return bool
     */
    private function luhnVerifyCardNum($number){
        $len = strlen(str_replace(' ','',$number));
        if(!$number || $len < 13 || $len > 19 ){
            return false;
        }

        $str = '';
        foreach (array_reverse(str_split($number)) as $i => $c) {
            $str .= ($i % 2 ? $c * 2 : $c);
        }
        $a = (array_sum(str_split($str)) % 10 == 0);
        return ($a ? true : false);
    }
    /**
     * 判断信用卡号是否合法
     * @param $number
     * @return bool
     */
    private function onlyVerifyCardNum($number){
        // Plug-in 32: Validate Credit Card
        //
        // This plug-in accepts a credit card number and
        // an expiry date and returns TRUE or FALSE,
        // depending on whether the details pass date
        // and checksum validation. The arguments required
        // are:
        //
        //  $number: Credit Card Number
        //  $expiry: Expiry date in the form:
        //    07/12 or 0712 (for July, 2012)
        $len = strlen(str_replace(' ','',$number));
        if(!$number || $len < 13 || $len > 19 ){
            return false;
        }
        $number = preg_replace('/[^\d]/', '', $number);
        $left   = substr($number, 0, 4);
        $cclen  = strlen($number);
        $chksum = 0;
        // Diners Club
        if (($left >= 3000) && ($left <= 3059) ||
            ($left >= 3600) && ($left <= 3699) ||
            ($left >= 3800) && ($left <= 3889)
        ) {
            if ($cclen != 14) {
                return false;
            }
        }
        // JCB
        if (($left >= 3088) && ($left <= 3094) ||
            ($left >= 3096) && ($left <= 3102) ||
            ($left >= 3112) && ($left <= 3120) ||
            ($left >= 3158) && ($left <= 3159) ||
            ($left >= 3337) && ($left <= 3349) ||
            ($left >= 3528) && ($left <= 3589)
        ) {
            if ($cclen != 16) {
                return false;
                // American Express
            } elseif (($left >= 3400) && ($left <= 3499) ||
                ($left >= 3700) && ($left <= 3799)
            ) {
                if ($cclen != 15) {
                    return false;
                } elseif (($left >= 3890) && ($left <= 3899)) { // Carte Blanche
                    if ($cclen != 14) {
                        return false;
                        // Visa
                    } elseif (($left >= 4000) && ($left <= 4999)) {
                        if ($cclen != 13 && $cclen != 16) {
                            return false;
                            // MasterCard
                        } elseif (($left >= 5100) && ($left <= 5599)) {
                            if ($cclen != 16) {
                                return false;
                                // Australian BankCard
                            } elseif ($left == 5610) {
                                if ($cclen != 16) {
                                    return false;
                                    // Discover
                                } elseif ($left == 6011) {
                                    if ($cclen != 16) {
                                        return false;
                                    } else {
                                        // Unknown
                                        return false;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
        for ($j = 1 - ($cclen % 2); $j < $cclen; $j += 2) {
            $chksum += substr($number, $j, 1);
        }
        for ($j = $cclen % 2; $j < $cclen; $j += 2) {
            $d = substr($number, $j, 1) * 2;
            $chksum += $d < 10 ? $d : $d - 9;
        }
        if ($chksum % 10 != 0) {
            return false;
        }
        return true;
    }
    /**
     * 取得信用卡类型
     * @param $Number 卡号
     * @return string
     * @author ZhouHaoHua <53027327@qq.com>
     */
    public function getType($Number) {
        $CardName     = '';
        $NumberLeft   = substr($Number, 0, 4);
        $NumberLength = strlen($Number);
        if ($NumberLeft >= 3000 and $NumberLeft <= 3059) {
            $CardName     = "Diners Club";
            $ShouldLength = 14;
        } elseif ($NumberLeft >= 3600 and $NumberLeft <= 3699) {
            $CardName     = "Diners Club";
            $ShouldLength = 14;
        } elseif ($NumberLeft >= 3800 and $NumberLeft <= 3889) {
            $CardName     = "Diners Club";
            $ShouldLength = 14;
        } elseif ($NumberLeft >= 3400 and $NumberLeft <= 3499) {
            $CardName     = "American Express";
            $ShouldLength = 15;
        } elseif ($NumberLeft >= 3700 and $NumberLeft <= 3799) {
            $CardName     = "American Express";
            $ShouldLength = 15;
        } elseif ($NumberLeft >= 3528 and $NumberLeft <= 3589) {
            $CardName     = "JCB";
            $ShouldLength = 16;
        } elseif ($NumberLeft >= 3890 and $NumberLeft <= 3899) {
            $CardName     = "Carte Blache";
            $ShouldLength = 14;
        } elseif ($NumberLeft >= 4000 and $NumberLeft <= 4999) {
            $CardName = "Visa";
            if ($NumberLength > 14) {
                $ShouldLength = 16;
            } elseif ($NumberLength < 14) {
                $ShouldLength = 13;
            }
        } elseif ($NumberLeft >= 5100 and $NumberLeft <= 5599) {
            $CardName     = "MasterCard";
            $ShouldLength = 16;
        } elseif ($NumberLeft == 5610) {
            $CardName     = "Australian BankCard";
            $ShouldLength = 16;
        } elseif ($NumberLeft == 6011) {
            $CardName     = "Discover/Novus";
            $ShouldLength = 16;
        }
        return $CardName;
    }
}

